package utils2

import (
	"bytes"
	"gitee.com/chejiangyi/bsfgo/core/utils"
	"github.com/gin-gonic/gin"
	"io"
	"reflect"
	"strings"
)

var WebUtil = &WebUtilTool{}

type WebUtilTool struct{}

func (m *WebUtilTool) GetRequestParam(c *gin.Context, key string, defaultValue any) any {
	// 尝试从各种位置获取参数
	if value, ex := c.GetQuery(key); ex {
		return m.stringConvertTo(value, defaultValue)
	}
	if value, ex := c.GetPostForm(key); ex {
		return m.stringConvertTo(value, defaultValue)
	}
	if value, ex := c.Params.Get(key); ex {
		return m.stringConvertTo(value, defaultValue)
	}
	return defaultValue
}

func (*WebUtilTool) stringConvertTo(fromValue any, toValue any) any {
	fromType := reflect.ValueOf(fromValue)
	toType := reflect.ValueOf(toValue)
	if fromType.Kind() == toType.Kind() {
		return fromValue
	}
	switch toValue.(type) {
	case string:
		return utils.ConvertUtil.ToString(fromValue)
	case int:
		return utils.ConvertUtil.ToInt(fromValue)
	case float64:
		return utils.ConvertUtil.ToFloat64(fromValue)
	case bool:
		return utils.ConvertUtil.ToBool(fromValue)
	default:
		return utils.ConvertUtil.ToString(fromValue)
	}
}

func (m *WebUtilTool) GetRequestInfo(c *gin.Context) map[string]interface{} {
	// 记录请求信息
	request := map[string]interface{}{
		"method": c.Request.Method,
		"path":   c.Request.URL.Path,
		"query":  c.Request.URL.RawQuery,
	}
	// 记录token(兼容)
	tokenHeader := []string{"Token", "X-Token", "Login-Token"}
	for _, h := range tokenHeader {
		v := c.Request.Header.Get(h)
		if !utils.StringUtil.IsEmpty(v) {
			request[h] = v
		}
	}
	// 记录请求体（非文件上传）
	if m.HeaderContentTypeIsJson(c) {
		body := m.GetBody(c)
		request["body"] = string(body)
	}
	return request
}

func (*WebUtilTool) HeaderContentTypeIsJson(c *gin.Context) bool {
	return strings.Contains(strings.ToLower(c.Request.Header.Get("Content-Type")), "application/json")
}

func (*WebUtilTool) GetBody(c *gin.Context) []byte {
	cache := WebUtil.GetBodyCache(c)
	if len(cache) > 0 {
		return cache
	} else {
		body, _ := io.ReadAll(c.Request.Body)
		c.Request.Body = io.NopCloser(bytes.NewBuffer(body)) // 重置 Body
		return body
	}
}

func (*WebUtilTool) SetBodyCache(c *gin.Context, bodyBytes []byte) {
	c.Set("_cachedBody", bodyBytes)
}

func (*WebUtilTool) GetBodyCache(c *gin.Context) []byte {
	if data, exist := c.Get("_cachedBody"); exist {
		return data.([]byte)
	} else {
		return nil
	}
}

func (*WebUtilTool) AbortResponseText(c *gin.Context, status int, text string) {
	c.AbortWithStatus(status)
	c.String(status, text)
}
